package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.json.JSONUtil;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageBean;
import com.zzyl.dto.*;
import com.zzyl.entity.*;
import com.zzyl.enums.BalanceStatusEnum;
import com.zzyl.enums.CheckInStatusEnum;
import com.zzyl.mapper.*;
import com.zzyl.service.CheckInService;
import com.zzyl.service.ElderService;
import com.zzyl.vo.*;
import com.zzyl.vo.retreat.ElderVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

@Service
public class CheckInServiceImpl implements CheckInService {
    @Autowired
    private ElderService elderService;
    @Autowired
    private CheckInMapper checkInMapper;
    @Autowired
    private CheckInConfigMapper checkInConfigMapper;
    @Autowired
    private ContractMapper contractMapper;

    @Autowired
    private BedMapper bedMapper;
    @Autowired
    private ElderMapper elderMapper;
    @Autowired
    MemberElderMapper memberElderMapper;
    @Autowired
    MemberMapper memberMapper;
    @Autowired
    BalanceMapper balanceMapper;

    /**
     * 分页查询
     *
     * @param elderName 老人姓名，模糊查询
     * @param idCardNo  身份证号，精确查询
     * @param pageNum   页码
     * @param pageSize  页面大小
     * @return 分页结果
     */
    @Override
    public PageBean<CheckInPageQueryVo> pageQuery(String elderName, String idCardNo, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);

        //老人姓名，模糊查询，这里进行预处理
        elderName = CharSequenceUtil.isBlank(elderName) ? null : "%" + elderName + "%";

        //这里只查询入住状态的
        Page<CheckInPageQueryVo> pageResult = checkInMapper.selectByPage(elderName, idCardNo, CheckInStatusEnum.PROGRESSING.getOrdinal());
        return PageBean.of(pageResult, CheckInPageQueryVo.class);
    }

    /**
     * 入住详情
     *
     * @param id 入住id
     * @return 入住详情
     */
    @Override
    public CheckInDetailVo detail(Long id) {
        //入住信息
        CheckIn checkIn = checkInMapper.selectById(id);

        //老人信息
        ElderVo elderVo = elderService.selectByPrimaryKey(checkIn.getElderId());
        CheckInElderVo checkInElderVo = BeanUtil.toBean(elderVo, CheckInElderVo.class);
        checkInElderVo.setOneInchPhoto(elderVo.getImage());

        //入住配置信息
        CheckInConfig checkInConfig = checkInConfigMapper.findCurrentConfigByElderId(checkIn.getElderId());

        //合同信息
        Contract contract = contractMapper.selectByContractNo(checkIn.getRemark());

        //封装响应信息
        CheckInDetailVo checkInDetailVo = new CheckInDetailVo();
        checkInDetailVo.setCheckInElderVo(checkInElderVo);
        checkInDetailVo.setElderFamilyVoList(JSONUtil.toList(checkIn.getOtherApplyInfo(), ElderFamilyVo.class));
        checkInDetailVo.setCheckInConfigVo(BeanUtil.toBean(checkInConfig, CheckInConfigVo.class));
        checkInDetailVo.setCheckInContractVo(BeanUtil.toBean(contract, CheckInContractVo.class));
        return checkInDetailVo;
    }

    @Override
    public void add(CheckInApplyDto dto) {
        //1,(床位表)更新床位信息
        //根据传入参数获取配置信息
        CheckInConfigDto dto1 = dto.getCheckInConfigDto();
        //根据配置信息设置床位id的启用状态
        Bed bed = Bed.builder().bedStatus(1).id(dto1.getBedId()).build();
        //修改床位的信息
        bedMapper.update(bed);
        //根据配置信息id查询,在此时用不上，但是在下面第二个的老人床位绑定用得上
        bed = bedMapper.selectid(dto1.getBedId());


        //2,(老人表)新增老人(或更新，老人可能以前入住过。如果数据库存在老人信息就是更新，不存在就是新增)
        //根据传入参数获取老人信息
        CheckInElderDto elderDto = dto.getCheckInElderDto();
        //将老人传入参数dto里面的数据复制到老人pojo里面，因为是插入或者是新增，必须要转换为跟数据库表对应的pojo类里面，这样才能新增或者是修改
        Elder elder = BeanUtil.toBean(elderDto, Elder.class);
        //因为传入参数dto里面的照片名字和pojo里面的名字不一样，pojo里面的是Image，dto里面的是OneInchPhoto，所以复制的时候，没有把照片复制要自己单独设置一下，
        elder.setImage(elderDto.getOneInchPhoto());
        //0为入住中，1已退住，同理传入参数中没有状态参数，所以要自己设置，既然已经是填了入住信息，那就是入住中，为0
        elder.setStatus(0);
        //根据床位信息获取床位编号，并将床位编号赋值给老人
        elder.setBedNumber(bed.getBedNumber());
        //在老人表中插入这条数据，并且在xml文件中，写主键自增返回
        elderMapper.insert(elder);

        //3，(会员表，老人和会员关系表)新增老人家属信息
        //根据传入参数dto获取老人家属的信息，因为老人的家属可能不止一个，所以得用集合来把老人家属的信息来封装起来
        List<ElderFamilyDto> familyDtos = dto.getElderFamilyDtoList();
        //用for循环来遍历集合中每个老人家属的信息
        familyDtos.forEach(familyDto -> {
            //调用会员表的pojo，因为会员表有个@SuperBuilder，可以自动生成一个builder方法，就不用new出来，直接调用，然后设置pojo里面的名字和手机号属性,返回一个完整的老人家属信息
            Member member = Member.builder()
                    .phone(familyDto.getPhone())
                    .name(familyDto.getName())
                    .build();
            //将得到的每一个老人家属信息，都添加到会员表中
            memberMapper.save(member);

            //老人和会员客户(也就是会员或者叫老人家属)表对应的pojo，设置会员的id和老人的id进行关联，然后加上备注
            MemberElder memberElder = MemberElder.builder()
                    .memberId(member.getId())
                    .elderId(elder.getId())
                    .remark(familyDto.getKinship())
                    .build();
            //再将老人和会员的关系数据添加到老人和会员关系表中
            memberElderMapper.add(memberElder);
        });

        //4,(入住表)新增入住信息
        //用hutool工具包里面的RandomUtil方法，生成一个随机数，这个就不用自己导包，然后手动创建，直接调用hutool工具包很方便
        String checkInCode = "RZ" + RandomUtil.randomNumbers(12);
        //手动new一个CheckIn对象，
        CheckIn checkIn = new CheckIn();
        //往CheckIn里面设置code信息
        checkIn.setCheckInCode(checkInCode);
        //之前已经将老人的信息加入到数据库中了，在上面已经创建并调用过elder对象，现在只需要调用elder对象获取老人的姓名添加到入住信息中去，
        checkIn.setTitle(elder.getName() + "的入住申请");
        //同理调用elder对象获取id并封装到入住信息表中
        checkIn.setElderId(elder.getId());
        //获取当前时间并赋值
        checkIn.setCheckInTime(LocalDateTime.now());
        //因为现在还没有写登录，没有jwt令牌，获取不了登陆人的信息，所以暂时先做个假的，等做了登录，再来完善
        checkIn.setApplicat("管理员");
        //现在关于申请人的一切信息都先做个假的，等做了登录功能再来完善
        checkIn.setDeptNo("100001001000000");
        checkIn.setApplicatId(1671403256519078138L);
        //设置入住信息的状态，既然都到这了，那肯定是已经填过表签过合同了，那肯定就是入住中了，不过也可以根据实际情况来默认入住状态
        checkIn.setStatus(0);//0入住中，1已退住
        //这里说的其他申请信息就是老人家属的信息，调用hutool工具包中的jsonutil.tojsonStr方法，将传入的老人家属信息转化为json格式并存储在其他申请信息这个属性里面
        checkIn.setOtherApplyInfo(JSONUtil.toJsonStr(dto.getElderFamilyDtoList()));
        //添加这条数据到入住信息表中
        checkInMapper.insert(checkIn);

        //5,(入住配置表)新增入住配置(就是选套餐之类的)
        //根据传入参数，获取入住配置信息的dto，并封装到pojo里面
        CheckInConfig checkInConfig = BeanUtil.toBean(dto.getCheckInConfigDto(), CheckInConfig.class);
        //pojo里面有老人id，所以要根据之前的老人信息获取老人id，并封装到里面
        checkInConfig.setElderId(elder.getId());
        //pojo里面有老人床位编号，所以需要获取老人床位编号并封装到里面，
        checkInConfig.setBedNumber(bed.getBedNumber());
        //pojo里面有老人入住编码，所以需要获取老人入住编码
        checkInConfig.setCheckInCode(checkIn.getCheckInCode());
        //根据传入参数获取楼层id，房间id，床位id，楼层名称，房间编号
        String remark = dto.getCheckInConfigDto().getFloorId()
                + ":" + dto.getCheckInConfigDto().getRoomId()
                + ":" + dto.getCheckInConfigDto().getBedId()
                + ":" + dto.getCheckInConfigDto().getFloorName()
                + ":" + dto.getCheckInConfigDto().getCode();
        //设置备注信息
        checkInConfig.setRemark(remark);
        //添加这一条入住配置信息到数据库中
        checkInConfigMapper.insert(checkInConfig);

        //(合同表)6,新增合同，如果入住开始时间小于当前时间
        //生成入住合同编号
        String contractNo = "HT" + RandomUtil.randomNumbers(12);
        //将合同的传入参数dto转化为pojo
        Contract contract = BeanUtil.toBean(dto.getCheckInContractDto(), Contract.class);
        //设置合同编号
        contract.setContractNo(contractNo);
        //设置入住编号
        contract.setCheckInNo(checkInCode);
        //设置老人编号
        contract.setElderId(elder.getId());
        //设置老人姓名
        contract.setElderName(elder.getName());
        //设置合同状态,1签了合同，0没签合同
        contract.setStatus(1);
        //根据最一开始获取的配置信息设置开始和结束时间
        contract.setStartTime(dto1.getCheckInStartTime());
        contract.setEndTime(dto1.getCheckInEndTime());
        //将这一条合同信息添加到数据库中
        contractMapper.insert(contract);

        //(余额表)7,新增或更新余额信息
        Balance balance = new Balance();
        balance.setElderId(elder.getId());
        balance.setElderName(elder.getName());
        balance.setBedNo(elder.getBedNumber());
        balance.setDepositAmount(checkInConfig.getDepositAmount());
        //设置预付款金额为0
        balance.setPrepaidBalance(new BigDecimal(0));
        //设置欠费金额为0
        balance.setArrearsAmount(new BigDecimal(0));
        //设置余额状态为正常，并且设置序号
        balance.setStatus(BalanceStatusEnum.NORMAL.getOrdinal());

        //调用mapper层根据id查询剩余的钱
        Balance balance1 = balanceMapper.selectByElderId(elder.getId());
        //判断剩余的钱是否为空，如果不为空，则将这个空的余额更新
        if (ObjectUtil.isNotEmpty(balance1)){
            balance.setId(balance1.getId());
            balanceMapper.updateByPrimaryKeySelective(balance);
        }else {
            balanceMapper.insert(balance);
        }

        //(账单表)8,新增首月账单，生成首月账单




    }
}
